package org.canaan.aspose;

import com.aspose.cells.ICellsDataTable;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.canaan.http.UrlPairUtil;

import java.util.*;

/**
 @Author Canaan
 @Date 2017/11/9 */
public class CollectionCellsTable implements ICellsDataTable {

    private final List<Object> dataRow;//数据
    private final String       columns[];
    private final int          describeDeep; //对象解析的深度
    private       int          index;//索引

    public CollectionCellsTable(Collection<?> dataRow) {
        //最大行数2000
        this(dataRow, 2000);
    }

    /**
     @param dataRow
     @param maxRow 指定可容纳的记录个数，默认2000
     */
    public CollectionCellsTable(Collection<?> dataRow, int maxRow) {
        this(dataRow, 2000, 2);
    }

    /**
     @param dataRow 数据
     @param maxRow 最大允许记录数据
     @param describeDeep 对象解析最大深度
     */
    public CollectionCellsTable(Collection<?> dataRow, int maxRow, int describeDeep) {
        this.describeDeep = describeDeep;

        Set<String> columnsSet = new TreeSet<>();
        if (CollectionUtils.isEmpty(dataRow)) {
            this.dataRow = new ArrayList<>();
            columns = new String[0];
            return;
        }

        this.dataRow = new ArrayList<>();
        if (dataRow.size() > maxRow) {
            throw new IllegalStateException("无法创建CollectionCellsTable,数据超过" + maxRow + "行");
        }
        for (Object item : dataRow) {
            this.dataRow.add(item);
        }

        Object record = this.dataRow.get(this.index);

        try {
            if (Map.class.isAssignableFrom(record.getClass())) {
                Map map = (Map) record;
                for (Object o : map.keySet()) {
                    if (!String.class.isAssignableFrom(o.getClass())) {
                        continue;
                    }
                    if (StringUtils.isBlank(o.toString())) {
                        continue;
                    }
                    if (map.get(o) instanceof Class) {
                        continue;
                    }
                    String prefix = o.toString();
                    columnsSet.add(prefix);
                    describe(prefix, map.get(o), columnsSet, 1);
                }
            } else {
                Map<String, Object> beanMap = PropertyUtils.describe(record);
                for (String key : beanMap.keySet()) {
                    if (StringUtils.isBlank(key)) {
                        continue;
                    }
                    if (beanMap.get(key) instanceof Class) {
                        continue;
                    }
                    columnsSet.add(key);
                    describe(key, beanMap.get(key), columnsSet, 1);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        columns = columnsSet.toArray(new String[columnsSet.size()]);
    }


    private void describe(String prefix, Object obj, Set<String> columnsSet, int currentDeep) {
        if (currentDeep > this.describeDeep) {
            return;
        }

        if (obj == null) {
            return;
        }

        if (UrlPairUtil.isBaseType(obj)) {
            return;
        }

        if (Map.class.isAssignableFrom(obj.getClass())) {
            Map map = (Map) obj;
            for (Object o : map.keySet()) {
                if (!String.class.isAssignableFrom(o.getClass())) {
                    continue;
                }
                if (StringUtils.isBlank(o.toString())) {
                    continue;
                }
                if (map.get(o) instanceof Class) {
                    continue;
                }
                String item = prefix + "|" + o.toString();
                columnsSet.add(item);
                describe(item, map.get(o), columnsSet, currentDeep++);
            }
        } else {
            Map<String, Object> beanMap;
            try {
                beanMap = PropertyUtils.describe(obj);
            } catch (Exception e) {
                return;
            }
            for (String key : beanMap.keySet()) {
                if (StringUtils.isBlank(key)) {
                    continue;
                }
                if (beanMap.get(key) instanceof Class) {
                    continue;
                }
                String item = prefix + "|" + key;
                columnsSet.add(item);
                describe(item, beanMap.get(key), columnsSet, currentDeep++);
            }
        }
    }


    /**
     初始化方法
     */
    @Override
    public void beforeFirst() {
        index = -1;
    }

    /**
     WorkbookDesigner自动调用
     会将this.getColumns()方法所返回的列 按照顺序调用改方法
     */
    @Override
    public Object get(int columnIndex) {
        if (index < 0 || index >= this.getCount()) {
            return null;
        }
        Object record = this.dataRow.get(index);
        String columnName = this.columns[columnIndex];

        try {
            return PropertyUtils.getProperty(record, columnName.replace("|", "."));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    /**
     根据columnName返回数据
     */
    @Override
    public Object get(String columnName) {
        Object record = this.dataRow.get(this.index);
        try {
            return PropertyUtils.getProperty(record, columnName);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     获得列集合
     */
    @Override
    public String[] getColumns() {
        return this.columns;
    }


    @Override
    public int getCount() {
        return this.dataRow.size();
    }

    @Override
    public boolean next() {
        index += 1;
        return index < this.getCount();
    }
}
